package com.fengwk.support.spring.boot.config;

import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import java.net.MalformedURLException;
import java.net.URL;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.pegdown.PegDownProcessor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Import;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;

import com.fengwk.support.util.DownloadUtils;
import com.fengwk.support.util.ResultUtils;
import com.fengwk.support.util.WebUtils;

import io.github.swagger2markup.Swagger2MarkupConfig;
import io.github.swagger2markup.Swagger2MarkupConverter;
import io.github.swagger2markup.builder.Swagger2MarkupConfigBuilder;
import io.github.swagger2markup.markup.builder.MarkupLanguage;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;

@ConfigurationProperties("swagger")
public abstract class AbstractSwagger2Config extends WebMvcConfigurerAdapter {

	private Boolean enable;
	private String basePackage;
	private String title;
	private String description;
	private String termsOfServiceUrl;
	private String version;
	private String apiDoc;
	
	public String swagger2MarkupConverter(HttpServletRequest request, MarkupLanguage markupLanguage) {
		Swagger2MarkupConfig swagger2MarkupConfig = new Swagger2MarkupConfigBuilder().withMarkupLanguage(markupLanguage).build();
		URL url = null;
		try {
			url = new URL(WebUtils.getSelfUrl(request) + apiDoc);
		} catch (MalformedURLException e) {
			e.printStackTrace();
		}
		if (url != null) {
			return Swagger2MarkupConverter.from(url).withConfig(swagger2MarkupConfig).build().toString();
		}
		return null;
	}
	
	@Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler("/js/**").addResourceLocations("classpath:/js/");
        registry.addResourceHandler("swagger-ui.html")
                .addResourceLocations("classpath:/META-INF/resources/");
        registry.addResourceHandler("/webjars/**")
                .addResourceLocations("classpath:/META-INF/resources/webjars/");
    }
	
	@Bean
	protected Docket swagger2() {
		return new Docket(DocumentationType.SWAGGER_2)
				.apiInfo(new ApiInfoBuilder()
						.title(title)
						.description(description)
						.termsOfServiceUrl(termsOfServiceUrl)
						.version(version)
						.build())
				.select()
				.apis(RequestHandlerSelectors.basePackage(basePackage))
				.paths(enable ? PathSelectors.any() : PathSelectors.none())
				.build();
	}
	
	@Bean
	protected Swagger2Controller swagger2Controller() {
		return new Swagger2Controller();
	}
	
	public Boolean getEnable() {
		return enable;
	}

	public void setEnable(Boolean enable) {
		this.enable = enable;
	}

	public String getBasePackage() {
		return basePackage;
	}

	public void setBasePackage(String basePackage) {
		this.basePackage = basePackage;
	}

	public String getTitle() {
		return title;
	}

	public void setTitle(String title) {
		this.title = title;
	}

	public String getDescription() {
		return description;
	}

	public void setDescription(String description) {
		this.description = description;
	}

	public String getTermsOfServiceUrl() {
		return termsOfServiceUrl;
	}

	public void setTermsOfServiceUrl(String termsOfServiceUrl) {
		this.termsOfServiceUrl = termsOfServiceUrl;
	}

	public String getVersion() {
		return version;
	}

	public void setVersion(String version) {
		this.version = version;
	}

	public String getApiDoc() {
		return apiDoc;
	}

	public void setApiDoc(String apiDoc) {
		this.apiDoc = apiDoc;
	}
	

	private static class DefaultSwagger2Config extends AbstractSwagger2Config {
		
	}

	@Api(tags={"swagger2"})
	@RequestMapping("/swagger2")
	private static class Swagger2Controller {

		@Autowired
		private HttpServletRequest request;
		@Autowired
		private HttpServletResponse response;
		@Autowired
		private AbstractSwagger2Config swagger2Config;
		
		private static final String API_NAME = "api";
		
		@ApiOperation("swagger2 主页")
		@GetMapping
		public String swagger2() {
			return "redirect:/swagger-ui.html";
		}
		
		@ApiOperation("swagger2 json 文档")
		@GetMapping("/doc")
		public String doc() {
			return "redirect:" + swagger2Config.getApiDoc();
		}
		
		@ApiOperation("下载 swagger2 md 文档")
		@ResponseBody
		@GetMapping("/md")
		public void md() {
			if (license()) {
				DownloadUtils.download(response, API_NAME + MarkupLanguage.MARKDOWN.getFileNameExtensions().get(0), swagger2Config.swagger2MarkupConverter(request, MarkupLanguage.MARKDOWN).getBytes());
			}
		}
		
		@ApiOperation("下载 swagger2 adoc 文档")
		@ResponseBody
		@GetMapping("/adoc")
		public void adoc() {
			if (license()) {
				DownloadUtils.download(response, API_NAME + MarkupLanguage.ASCIIDOC.getFileNameExtensions().get(0), swagger2Config.swagger2MarkupConverter(request, MarkupLanguage.ASCIIDOC).getBytes());
			}
		}
		
		@ApiOperation("下载 swagger2 txt 文档")
		@ResponseBody
		@GetMapping("/txt")
		public void txt() {
			if (license()) {
				DownloadUtils.download(response, API_NAME + MarkupLanguage.CONFLUENCE_MARKUP.getFileNameExtensions().get(0), swagger2Config.swagger2MarkupConverter(request, MarkupLanguage.CONFLUENCE_MARKUP).getBytes());
			}
		}
		
		@ApiOperation("下载 swagger2 html 文档")
		@ResponseBody
		@GetMapping("/html")
		public void html() {
			if (license()) {
				DownloadUtils.download(response, API_NAME + ".html", markdownHtml().getBytes());
			}
		}
		
		private String markdownHtml() {
			PegDownProcessor pdp = new PegDownProcessor(Integer.MAX_VALUE);
	        return pdp.markdownToHtml(swagger2Config.swagger2MarkupConverter(request, MarkupLanguage.MARKDOWN));
		}
		
		private boolean license() {
			if (!swagger2Config.getEnable()) {
				ResultUtils.returnJsonResult(request, response, false, "访问未经许可");
				return false;
			}
			return true;
		}
		
	}
	
	@Retention(value = java.lang.annotation.RetentionPolicy.RUNTIME)
	@Target(value = { java.lang.annotation.ElementType.TYPE })
	@Documented
	@springfox.documentation.swagger2.annotations.EnableSwagger2
	@Import({DefaultSwagger2Config.class})
	public static @interface EnableSwagger2 {

	}
	
}
